/*

This file is part of roomyak.

Copyright (C) 2008 Pixecur Technologies Incorporated (Esotera).
Visit Esotera at http://www.esoteras3.com
 
roomyak is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
 
roomyak is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with roomyak; see the file COPYING.  If not, write to 
Pixecur Technologies, 213-31 Peet Street, St. John's, NL, A1B 3W8. 
 
Linking this library statically or dynamically with other modules is
making a combined work based on this library.  Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.
 
*/

package com.datasentinel.util.io;

import java.io.DataInput;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.atomic.AtomicLong;

public class CounterDataInputStream extends InputStream implements DataInput
{
	private AtomicLong readByteCount = new AtomicLong();
	private DataInputStream dataInputStream; 
	
	public CounterDataInputStream(DataInputStream dataInputStream)
	{
		this.dataInputStream = dataInputStream;
	}
	
	/**
	 * @return the number of bytes that were acquired (read or skipped) from the input stream
	 */
	public long getReadByteCount()
	{
		return readByteCount.get();
	}

    /**
     * Increases the written counter by the specified value
     * until it reaches Integer.MAX_VALUE.
     */
    private void incCount(int value) {
        readByteCount.addAndGet(value);
    }
	
    private void incCount(long value) {
        readByteCount.addAndGet(value);
    }
    
	@Override
	public boolean readBoolean() throws IOException
	{
		boolean b = dataInputStream.readBoolean();
		incCount(1);
		return b;
	}

	@Override
	public byte readByte() throws IOException
	{
		byte b = dataInputStream.readByte();
		incCount(1);
		return b;
	}

	@Override
	public char readChar() throws IOException
	{
		char c = dataInputStream.readChar();
		incCount(2);
		return c;
	}

	@Override
	public double readDouble() throws IOException
	{
		double d = dataInputStream.readDouble();
		incCount(8);
		return d;
	}

	@Override
	public float readFloat() throws IOException
	{
		float f = dataInputStream.readFloat();
		incCount(4);
		return f;
	}

	@Override
	public void readFully(byte[] b) throws IOException
	{
		dataInputStream.readFully(b);
		incCount(b.length);
	}

	@Override
	public void readFully(byte[] b, int off, int len) throws IOException
	{
		dataInputStream.readFully(b, off, len);
		incCount(len);
	}

	@Override
	public int readInt() throws IOException
	{
		int i = dataInputStream.readInt();
		incCount(4);
		return i;
	}

	@Deprecated
	@Override
	public String readLine() throws IOException
	{
		throw new UnsupportedOperationException("Method readLine() is not supported by the class CounterDataInputStream");
	}


	
	@Override
	public long readLong() throws IOException
	{
		long l = dataInputStream.readLong();
		incCount(8);
		return l;
	}

	@Override
	public short readShort() throws IOException
	{
		short s = dataInputStream.readShort();
		incCount(2);
		return s;
	}

	@Override
	public String readUTF() throws IOException
	{
		return DataInputStream.readUTF(this);
	}

	@Override
	public int readUnsignedByte() throws IOException
	{
		int ub = dataInputStream.readUnsignedByte();
		incCount(1);
		return ub;
	}

	@Override
	public int readUnsignedShort() throws IOException
	{
		int ushort = dataInputStream.readUnsignedShort();
		incCount(2);
		return ushort;
	}

	@Override
	public int skipBytes(int n) throws IOException
	{
		int bytesSkipped = dataInputStream.skipBytes(n);
		incCount(bytesSkipped);
		return bytesSkipped;
	}

	@Override
	public int read() throws IOException
	{
		int c = dataInputStream.read();
		incCount(1);
		return c;
	}

	@Override
	public int read(byte[] b) throws IOException
	{
		int readCount = dataInputStream.read(b);
		incCount(readCount);
		return readCount;
	}
	
	@Override
	public int read(byte[] b, int off, int len) throws IOException
	{
		int readCount = dataInputStream.read(b, off, len);
		incCount(readCount);
		return readCount;
	}
	
	@Override
	public long skip(long n) throws IOException
	{
		long skipCount = dataInputStream.skip(n);
		incCount(skipCount);
		return skipCount;
	}
	
	@Override
	public void close() throws IOException
	{
		dataInputStream.close();
	}
	
	@Override
	public synchronized void reset() throws IOException
	{
		dataInputStream.reset();
	}
	
	@Override
	public int available() throws IOException
	{
		return dataInputStream.available();
	}
	
	@Override
	public boolean markSupported()
	{
		return dataInputStream.markSupported();
	}
	
	@Override
	public synchronized void mark(int readlimit)
	{
		dataInputStream.mark(readlimit);
	}
}
